<template>
  <!--
  ------------------------------
  title: 弹窗标题
  initId: 初始化id，根据此id查找默认选择项
  multiple： 是否多选，false为单选
  editable： 是否可编辑，默认true
  ------------------------------
 -->
  <div class="tag-tree-selection">
    <el-input
      :placeholder="placeholder || '请选择' + treeProps.title"
      v-model="showValue"
      readonly
      :disabled="!editable"
      @click.native="openTree"
      :size="inputSize"
      ><i slot="suffix" v-if="editable" class="el-input__icon el-icon-close" @click.stop="clearSelection"></i
    ></el-input>
    <el-dialog
      :title="treeProps.title"
      :visible.sync="dialogVisible"
      top="10vh"
      :close-on-click-modal="false"
      :before-close="cancelSelect"
      append-to-body
      :class="'tree-selection tag-edit-dialog ' + dialogClass"
      width="30%"
      v-dialogMove
    >
      <div class="search-key clearfix">
        <el-input placeholder="请输入关键字" v-model="searchkey" size="small"></el-input>
        <div class="btn-box">
          <el-button type="primary" plain circle @click="expandAll(false)">
            <icon-svg name="iconWup"></icon-svg>
          </el-button>
          <el-button type="primary" plain circle @click="expandAll(true)">
            <icon-svg name="iconWdown"></icon-svg>
          </el-button>
        </div>
      </div>
      <el-tree
        :data="data"
        :props="treeProps"
        :show-checkbox="multiple ? true : false"
        :highlight-current="true"
        :default-checked-keys="selectVal.id"
        :node-key="treeProps.id"
        default-expand-all
        :expand-on-click-node="false"
        :check-strictly="true"
        :check-on-click-node="true"
        @check-change="checkChange"
        :filter-node-method="filter"
        ref="tree"
      >
        <span slot-scope="{ node, data }" class="tree-item">
          <el-radio v-model="selectVal.id[0]" :label="data[treeProps.id]" v-if="!multiple"></el-radio>
          <icon-svg name="iconFolder" v-if="folderIcon"></icon-svg>
          <span>{{ data[treeProps.label] }}</span>
        </span>
      </el-tree>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cancelSelect">取消</el-button>
        <el-button type="primary" @click="confirmSelection">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    data: {
      type: Array,
      required: true,
      default: () => []
    },
    placeholder: {
      type: String,
      default: ''
    },
    treeProps: {
      type: Object,
      required: true,
      default: () => {
        return { title: '', children: '_children', label: 'label', id: 'id' }
      }
    },
    initId: {
      type: [String, Number, Array],
      default: ''
    },
    multiple: {
      type: Boolean,
      default: false
    },
    editable: {
      type: Boolean,
      default: true
    },
    folderIcon: {
      type: Boolean,
      default: false
    },
    dialogClass: {
      default: ''
    },
    inputSize: {
      type: String,
      default: ''
    }
  },
  watch: {
    dialogVisible(val) {
      let id =
        typeof this.initId === 'string' || typeof this.initId === 'number'
          ? Array.of(this.initId)
          : Array.from(this.initId)
      if (val) this.calculateId(this.data, id)
    },
    searchkey(val) {
      this.$refs.tree.filter(val)
    },
    initId(val) {
      if (!val) this.showValue = ''
      else {
        let id = typeof this.initId === 'string' || typeof this.initId === 'number' ? Array.of(val) : Array.from(val)
        this.calculateId(this.data, id)
      }
    }
  },
  data() {
    return {
      radio: true,
      dialogVisible: false,
      searchkey: '',
      selectVal: {
        id: [],
        name: []
      },
      showValue: ''
    }
  },
  mounted() {
    this.$nextTick(() => {
      if (this.initId) {
        let id =
          typeof this.initId === 'string' || typeof this.initId === 'number'
            ? Array.of(this.initId)
            : Array.from(this.initId)
        this.calculateId(this.data, id)
      }
    })
  },
  methods: {
    openTree() {
      if (this.editable) this.dialogVisible = true
    },
    calculateId(datas, initIds) {
      let ids = []
      let names = []
      const calculate = (data, val) => {
        data.map(v => {
          val.forEach(item => {
            if (v[this.treeProps.id] === item) {
              if (this.multiple) {
                ids.push(v[this.treeProps.id])
                names.push(v[this.treeProps.label])
              } else {
                ids = [v[this.treeProps.id]]
                names = [v[this.treeProps.label]]
              }
            }
          })
          if (v[this.treeProps.children]) {
            let id =
              typeof this.initId === 'string' || typeof this.initId === 'number'
                ? Array.of(this.initId)
                : Array.from(this.initId)
            calculate(v[this.treeProps.children], id)
          }
        })
      }
      calculate(datas, initIds)
      this.selectVal.id = ids
      this.selectVal.name = names
      this.showValue = names.join(',')
    },
    expandAll(expand = true) {
      let allNodes = this.$refs.tree.store._getAllNodes()
      allNodes.forEach(item => {
        item.expanded = expand
      })
    },
    checkChange(node, selected) {
      if (!this.multiple) {
        if (selected) {
          this.selectVal.id = [node[this.treeProps.id]]
          this.selectVal.name = [node[this.treeProps.label]]
          this.$refs.tree.setCheckedKeys([node[this.treeProps.id]])
        } else {
          if (this.selectVal.id[0] === node[this.treeProps.id]) {
            this.$refs.tree.setCheckedKeys([node[this.treeProps.id]])
          }
        }
      } else {
        let index = this.selectVal.id.findIndex(id => id === node[this.treeProps.id])
        if (selected) {
          if (index < 0) {
            this.selectVal.id.push(node[this.treeProps.id])
            this.selectVal.name.push(node[this.treeProps.label])
            this.$refs.tree.setCheckedKeys(this.selectVal.id)
          }
        } else {
          if (index >= 0) {
            this.selectVal.id.splice(index, 1)
            this.selectVal.name.push(index, 1)
            this.$refs.tree.setCheckedKeys(this.selectVal.id)
          }
        }
      }
    },
    cancelSelect() {
      this.selectVal.id = []
      this.selectVal.name = []
      this.$refs.tree.setCheckedKeys([])
      this.dialogVisible = false
    },
    clearSelection() {
      this.selectVal.id = []
      this.selectVal.name = []
      this.showValue = ''
      this.$emit('confirm', this.multiple ? [] : '')
    },
    confirmSelection() {
      this.showValue = this.selectVal.name.join(',')
      this.$emit('confirm', this.multiple ? this.selectVal.id : this.selectVal.id[0])
      this.dialogVisible = false
    },
    filter(value, data) {
      if (!value) return true
      return data[this.treeProps.label].indexOf(value) !== -1
    }
  }
}
</script>

<style lang="scss">
.tag-tree-selection {
  .el-input__inner,
  .el-input.is-disabled .el-input__inner {
    cursor: pointer;
  }
}
.tree-selection {
  .el-tree {
    height: 30vh;
    margin-top: 10px;
    overflow-y: auto;
  }
  .search-key {
    position: relative;
    height: 32px;
    line-height: 32px;
    .el-input {
      width: auto;
      position: absolute;
      left: 0;
      right: 70px;
    }
    .btn-box {
      float: right;
      .el-button {
        padding: 4px;
      }
      .icon-svg {
        font-size: 14px;
      }
    }
  }
  .el-radio__label {
    display: none;
  }
  .el-radio {
    margin-right: 5px;
  }
  .tree-item {
    .icon-svg {
      font-size: 16px;
      vertical-align: middle;
      margin-right: 2px;
    }
  }
}
</style>
